#pragma once
#include "Socket.hpp"
#include <sys/epoll.h>
using namespace socket_ns;

class EpollServer
{
    const static int gnum = 64;

public:
    EpollServer(uint16_t port)
        : _port(port), _listenSock(std::make_unique<TcpSocket>())
    {
        // 1.初始化listenSock
        _listenSock->BuildListenServer(INetAddr("0", port));

        // 2.创建epoll
        _epfd = ::epoll_create(128);
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll_create error\n");
            exit(5);
        }
        LOG(INFO, "epoll_create success, epfd : %d\n", _epfd);

        // 告诉内核，关注listenSock的读事件
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listenSock->Socketfd();
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenSock->Socketfd(), &ev);
    }
    void HandlerEvent(int num)
    {
        for (int i = 0; i < num; i++)
        {
            uint32_t event = _revents[i].events;
            int fd = _revents[i].data.fd;
            // 读事件就绪
            if (event & EPOLLIN)
            {
                // 有新的连接建立
                if (fd == _listenSock->Socketfd())
                {
                    INetAddr clientAddr;
                    int newfd = _listenSock->Acceptor(clientAddr);
                    if (newfd < 0)
                        continue;

                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = newfd;
                    ::epoll_ctl(_epfd, EPOLL_CTL_ADD, newfd, &ev);
                    LOG(INFO, "get a new link, fd : %d\n", newfd);
                }
                else
                {
                    char buff[1024];
                    ssize_t n = ::recv(fd, buff, sizeof(buff) - 1, 0);
                    if (n > 0)
                    {
                        buff[n] = '\0';

                        LOG(INFO, "recv a message from %d\n", fd);
                        std::cout << buff << std::endl;

                        std::string echoStr = std::string("[server echo]# ") + buff;
                        ::send(fd, echoStr.c_str(), echoStr.size(), 0);
                    }
                    else if (n == 0)
                    {
                        LOG(INFO, "client is quit\n");
                        //del时需要保证fd是合法的，所有必须先del再close
                        ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
                        ::close(fd);
                    }
                    else
                    {
                        LOG(INFO, "recv error, quit\n");
                        ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
                        ::close(fd);
                    }
                }
            }
        }
    }
    void Loop()
    {
        int timeout = -1;
        while (true)
        {
            int n = epoll_wait(_epfd, _revents, gnum, timeout);
            switch (n)
            {
            case 0:
                LOG(DEBUG, "epoll_wait timeout...\n");
                break;
            case -1:
                LOG(DEBUG, "epoll_wait fail\n");
                break;
            default:
                LOG(DEBUG, "epoll_wait have event happend!, n = %d\n", n);
                // 有事件就绪，会严格按照下标顺序放到_revent数组中，只需要遍历前n个即可
                HandlerEvent(n);
                break;
            }
        }
    }
    ~EpollServer()
    {
        _listenSock->Close();
        if (_epfd >= 0)
            ::close(_epfd);
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listenSock;

    int _epfd;
    struct epoll_event _revents[gnum];
};